﻿/*
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace Jsil.Compiler
{
	class TypeCopier
	{
		ModuleBuilder _modBldr;
		internal TypeCopier(ModuleBuilder modBldr)
		{
			_modBldr=modBldr;
		}

		Dictionary<Type,TypeBuilder> _copiedTypes=new Dictionary<Type,TypeBuilder>();
		Dictionary<MethodInfo,MethodInfo> _copiedMethods=new Dictionary<MethodInfo,MethodInfo>();
		Dictionary<ConstructorInfo,ConstructorInfo> _copiedConstructors=new Dictionary<ConstructorInfo,ConstructorInfo>();
		Dictionary<FieldInfo,FieldBuilder> _copiedFields=new Dictionary<FieldInfo,FieldBuilder>();
		Dictionary<EventInfo,EventBuilder> _copiedEvents=new Dictionary<EventInfo,EventBuilder>();
		Dictionary<PropertyInfo,PropertyBuilder> _copiedProperties=new Dictionary<PropertyInfo,PropertyBuilder>();
		Dictionary<Type,Type> _createdTypes=new Dictionary<Type,Type>();
		internal Type CopyType(Type typeToCopy)
		{
			if (typeToCopy==null)
				return null;

			bool isGenericNonDefType=(typeToCopy.IsGenericType)&&(!typeToCopy.IsGenericTypeDefinition);
			bool isByRefType=(!typeToCopy.IsGenericType)&&(!typeToCopy.IsGenericTypeDefinition)&&(typeToCopy.IsByRef);
			bool breakRuntimeBlock=isGenericNonDefType||isByRefType;

			if (((typeToCopy.Assembly.GetName().Name!="Jsil.Runtime"))&&(!breakRuntimeBlock))
				return typeToCopy;
			TypeBuilder already;
			if (_copiedTypes.TryGetValue(typeToCopy,out already))
				return already;
			Type alreadyCreated;
			if (_createdTypes.TryGetValue(typeToCopy,out alreadyCreated))
				return alreadyCreated;

			#region special types
			if (typeToCopy.IsGenericParameter)
				return AddAlreadyCreated(typeToCopy,CopyType(typeToCopy.DeclaringType).GetGenericArguments()[typeToCopy.GenericParameterPosition]);

			if (typeToCopy.IsArray)
				return AddAlreadyCreated(typeToCopy,CopyType(typeToCopy.GetElementType()).MakeArrayType());

			if (isGenericNonDefType)
				return AddAlreadyCreated(typeToCopy,
					CopyType(typeToCopy.GetGenericTypeDefinition())
						.MakeGenericType(Array.ConvertAll(typeToCopy.GetGenericArguments(),item => CopyType(item)))
						);

			if (isByRefType)
				return AddAlreadyCreated(typeToCopy,CopyType(typeToCopy.GetElementType()).MakeByRefType());
			#endregion special types

			Type[] interfaces=typeToCopy.GetInterfaces();
			Type[] interfaces2=Array.ConvertAll(interfaces,item => CopyType(item));

			Type baseType=typeof(object);
			if (typeToCopy.BaseType!=baseType)
				baseType=CopyType(typeToCopy.BaseType);

			TypeBuilder result=typeToCopy.IsNested
				?((TypeBuilder)CopyType(typeToCopy.DeclaringType)).DefineNestedType(typeToCopy.Name,typeToCopy.Attributes,baseType,interfaces2)
				:_modBldr.DefineType((typeToCopy.FullName??typeToCopy.Name).Replace("Jsil.Runtime.","JsilRun."),typeToCopy.Attributes,baseType,interfaces2);
			_copiedTypes.Add(typeToCopy,result);

			Type[] genericArgs=typeToCopy.GetGenericArguments();
			if (genericArgs.Length!=0)
				result.DefineGenericParameters(Array.ConvertAll(genericArgs,item => item.Name));

			BindingFlags bindingFlags=BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static|BindingFlags.DeclaredOnly;
			foreach (ConstructorInfo item in typeToCopy.GetConstructors(bindingFlags))
				CopyConstructorNative(result,item);

			bool copyWholeClass=HaveAttribute(typeToCopy,typeof(CopyWholeClassAttribute));

			if (copyWholeClass)
				return CopyAllMembers(typeToCopy,result);
			else
			{
				if (typeToCopy.IsEnum)
					foreach (FieldInfo item in typeToCopy.GetFields())
						CopyFieldNative(result,item);

				if (interfaces.Length>0)
				{
					List<MethodDef> interfaceMethods=new List<MethodDef>();
					bool isInterfaceCol=Array.Find(typeToCopy.GetInterfaces(),item => (item.FullName!=null)&&(item.FullName.StartsWith("System.Collections.Generic.IEnumerable`1[")))!=null;
					foreach (Type item in interfaces)
						foreach (MethodInfo mi in item.GetMethods(bindingFlags))
						{
							MethodDef def=new MethodDef(mi);
							if (!interfaceMethods.Contains(def))
								interfaceMethods.Add(def);
						}
					if (interfaceMethods.Count>0)
					{
						MethodDef[] mis=Array.ConvertAll(typeToCopy.GetMethods(bindingFlags),item => new MethodDef(item));
						foreach (MethodDef item in interfaceMethods)
						{
							int pos=Array.IndexOf(mis,item);
							if (pos!=-1)
								CopyMethodNative(result,mis[pos].MethodInfo,isInterfaceCol?item.MethodInfo:null);
						}
					}
				}
			}

			if (typeof(Delegate).IsAssignableFrom(typeToCopy))
			{
				if (!copyWholeClass)
					foreach (MethodInfo item in typeToCopy.GetMethods(bindingFlags))
						CopyMethodNative(result,item);

				Type ttt=result.CreateType();
				_copiedTypes.Remove(typeToCopy);
				_createdTypes.Add(typeToCopy,ttt);
				return ttt;
			}

			return result;
		}

		Type AddAlreadyCreated(Type typeToCopy,Type typeCopy)
		{
			_createdTypes.Add(typeToCopy,typeCopy);
			return typeCopy;
		}

		struct MethodDef
		{
			string Name;
			Type ResultType;
			Type[] ParameterTypes;
			internal MethodInfo MethodInfo;

			public MethodDef(MethodInfo mi)
			{
				MethodInfo=mi;
				Name=mi.Name;
				int pos=Name.LastIndexOf('.');
				if (pos!=-1)
					Name=Name.Substring(pos+1);
				ResultType=mi.ReturnType;
				ParameterTypes=Array.ConvertAll(mi.GetParameters(),item => item.ParameterType);
			}

			public override bool Equals(object obj)
			{
				MethodDef o=(MethodDef)obj;
				return (o.Name==this.Name)&&(o.ResultType==this.ResultType)&&(CompareArgumentTypes(o.ParameterTypes,this.ParameterTypes));
			}

			public override int GetHashCode()
			{
				return base.GetHashCode();
			}

			bool CompareArgumentTypes(Type[] a1,Type[] a2)
			{
				if (a1.Length!=a2.Length)
					return false;
				int a=0;
				foreach (Type t in a1)
					if (t!=a2[a++])
						return false;
				return true;
			}

			public override string ToString()
			{
				return this.Name;
			}
		}

		internal MethodInfo CopyMethod(MethodInfo methodToCopy)
		{
			MethodInfo already;
			if (_copiedMethods.TryGetValue(methodToCopy,out already))
				return already;

			Type declType=methodToCopy.DeclaringType;
			Type typeCopy=CopyType(declType);
			if (IsDelegateDescendant(declType))
				return typeCopy.GetMethod(methodToCopy.Name);
			TypeBuilder typeBldr=typeCopy as TypeBuilder;
			if (typeBldr==null)
				if (declType==typeCopy)
					return methodToCopy;
				else
				{
					BindingFlags bf=(methodToCopy.IsPublic?BindingFlags.Public:BindingFlags.NonPublic)|(methodToCopy.IsStatic?BindingFlags.Static:BindingFlags.Instance);
					int parmsCount=methodToCopy.GetParameters().Length;
					MethodInfo result=Array.Find(typeCopy.GetMethods(bf),item => (item.Name==methodToCopy.Name)&&(item.GetParameters().Length==parmsCount));
					_copiedMethods.Add(methodToCopy,result);
					return result;
				}

			return CopyMethodNative(typeBldr,methodToCopy);
		}

		internal MethodInfo CopyMethodNative(TypeBuilder typeBldr,MethodInfo methodToCopy)
		{
			return CopyMethodNative(typeBldr,methodToCopy,null);
		}

		MethodInfo CopyMethodNative(TypeBuilder typeBldr,MethodInfo methodToCopy,MethodInfo interfaceDeclaration)
		{
			ParameterInfo[] parms=methodToCopy.GetParameters();
			Type[] parameterTypes=Array.ConvertAll(parms,item => CopyType(item.ParameterType));
			MethodInfo already;
			if (_copiedMethods.TryGetValue(methodToCopy,out already))
				return already;

			MethodBuilder result=typeBldr.DefineMethod(methodToCopy.Name,methodToCopy.Attributes,CopyType(methodToCopy.ReturnType),parameterTypes);
			if (interfaceDeclaration!=null)
				//http://stackoverflow.com/questions/1822047/how-to-emit-explicit-interface-implementation-using-reflection-emit
				//http://stackoverflow.com/questions/4801537/creating-a-dynamictype-in-net-implementing-an-interface-but-using-member-implem
				//http://stackoverflow.com/questions/14947225/why-does-interface-implementation-in-emit-with-explicit-overload-behave-differen
				typeBldr.DefineMethodOverride(result,interfaceDeclaration);

			int a=0;
			foreach (ParameterInfo item in parms)
				result.DefineParameter(++a,item.Attributes,item.Name);
			result.SetImplementationFlags(methodToCopy.GetMethodImplementationFlags());
			_copiedMethods.Add(methodToCopy,result);

			AnalyzeMethodBody(methodToCopy);
			return result;
		}

		internal ConstructorInfo CopyConstructor(ConstructorInfo constructorToCopy)
		{
			ConstructorInfo already;
			if (_copiedConstructors.TryGetValue(constructorToCopy,out already))
				return already;

			Type declType=constructorToCopy.DeclaringType;
			Type typeCopy=CopyType(declType);
			TypeBuilder typeBldr=typeCopy as TypeBuilder;
			if (typeBldr==null)
				if (declType==typeCopy)
					return constructorToCopy;
				else
				{
					BindingFlags bf=(constructorToCopy.IsPublic?BindingFlags.Public:BindingFlags.NonPublic)|(constructorToCopy.IsStatic?BindingFlags.Static:BindingFlags.Instance);
					int parmsCount=constructorToCopy.GetParameters().Length;
					ConstructorInfo result=Array.Find(typeCopy.GetConstructors(bf),item => (item.Name==constructorToCopy.Name)&&(item.GetParameters().Length==parmsCount));
					_copiedConstructors.Add(constructorToCopy,result);
					return result;
				}

			return CopyConstructorNative(typeBldr,constructorToCopy);
		}

		ConstructorInfo CopyConstructorNative(TypeBuilder typeBldr,ConstructorInfo constructorToCopy)
		{
			ParameterInfo[] parms=constructorToCopy.GetParameters();
			Type[] parameterTypes=Array.ConvertAll(parms,item => CopyType(item.ParameterType));
			ConstructorInfo already;
			if (_copiedConstructors.TryGetValue(constructorToCopy,out already))
				return already;

			ConstructorBuilder result=typeBldr.DefineConstructor(constructorToCopy.Attributes,constructorToCopy.CallingConvention,parameterTypes);
			int a=0;
			foreach (ParameterInfo item in parms)
				result.DefineParameter(++a,item.Attributes,item.Name);
			result.SetImplementationFlags(constructorToCopy.GetMethodImplementationFlags());
			_copiedConstructors.Add(constructorToCopy,result);

			AnalyzeMethodBody(constructorToCopy);
			return result;
		}

		internal FieldInfo CopyField(FieldInfo fieldToCopy)
		{
			FieldBuilder already;
			if (_copiedFields.TryGetValue(fieldToCopy,out already))
				return already;

			/ *TypeBuilder typeBldr=CopyType(fieldToCopy.DeclaringType) as TypeBuilder;
			if (typeBldr==null)
				return fieldToCopy;* /
			Type declType=fieldToCopy.DeclaringType;
			Type typeCopy=CopyType(declType);
			TypeBuilder typeBldr=typeCopy as TypeBuilder;
			if (typeBldr==null)
				//if (declType==typeCopy)
				return fieldToCopy;
			/ *else
				return typeCopy.GetField(fieldToCopy.Name,(fieldToCopy.IsPublic?BindingFlags.Public:BindingFlags.NonPublic)|(fieldToCopy.IsStatic?BindingFlags.Static:BindingFlags.Instance));* /

			return CopyFieldNative(typeBldr,fieldToCopy);
		}

		FieldInfo CopyFieldNative(TypeBuilder typeBldr,FieldInfo fieldToCopy)
		{
			FieldBuilder result=typeBldr.DefineField(fieldToCopy.Name,CopyType(fieldToCopy.FieldType),fieldToCopy.Attributes);
			_copiedFields.Add(fieldToCopy,result);
			if ((int)(fieldToCopy.Attributes&FieldAttributes.HasDefault)!=0)
				result.SetConstant(fieldToCopy.GetRawConstantValue());
			return result;
		}

		internal object CopyEvent(EventInfo eventToCopy)
		{
			EventBuilder already;
			if (_copiedEvents.TryGetValue(eventToCopy,out already))
				return already;

			/ *TypeBuilder typeBldr=CopyType(fieldToCopy.DeclaringType) as TypeBuilder;
			if (typeBldr==null)
				return fieldToCopy;* /
			Type declType=eventToCopy.DeclaringType;
			Type typeCopy=CopyType(declType);
			TypeBuilder typeBldr=typeCopy as TypeBuilder;
			if (typeBldr==null)
				//if (declType==typeCopy)
				return eventToCopy;
			/ *else
				return typeCopy.GetField(fieldToCopy.Name,(fieldToCopy.IsPublic?BindingFlags.Public:BindingFlags.NonPublic)|(fieldToCopy.IsStatic?BindingFlags.Static:BindingFlags.Instance));* /

			return CopyEventNative(typeBldr,eventToCopy);
		}

		EventBuilder CopyEventNative(TypeBuilder typeBldr,EventInfo eventToCopy)
		{
			EventBuilder result=typeBldr.DefineEvent(eventToCopy.Name,eventToCopy.Attributes,CopyType(eventToCopy.EventHandlerType));
			_copiedEvents.Add(eventToCopy,result);

			result.SetAddOnMethod((MethodBuilder)CopyMethod(eventToCopy.GetAddMethod()));
			result.SetRemoveOnMethod((MethodBuilder)CopyMethod(eventToCopy.GetRemoveMethod()));
			MethodInfo mi=eventToCopy.GetRaiseMethod();
			if (mi!=null)
				result.SetRaiseMethod((MethodBuilder)CopyMethod(mi));
			foreach (MethodInfo item in eventToCopy.GetOtherMethods())
				result.AddOtherMethod((MethodBuilder)CopyMethod(item));

			return result;
		}

		internal PropertyInfo CopyProperty(PropertyInfo propertyToCopy)
		{
			PropertyBuilder already;
			if (_copiedProperties.TryGetValue(propertyToCopy,out already))
				return already;

			TypeBuilder typeBldr=CopyType(propertyToCopy.DeclaringType) as TypeBuilder;
			if (typeBldr==null)
				return propertyToCopy;

			return CopyPropertyNative(typeBldr,propertyToCopy);
		}

		PropertyInfo CopyPropertyNative(TypeBuilder typeBldr,PropertyInfo propertyToCopy)
		{
			PropertyBuilder result=typeBldr.DefineProperty(propertyToCopy.Name,propertyToCopy.Attributes,CopyType(propertyToCopy.PropertyType),Array.ConvertAll(propertyToCopy.GetIndexParameters(),item => CopyType(item.ParameterType)));
			if ((int)(propertyToCopy.Attributes&PropertyAttributes.HasDefault)!=0)
				result.SetConstant(propertyToCopy.GetRawConstantValue());

			if (propertyToCopy.CanRead)
				result.SetGetMethod((MethodBuilder)CopyMethod(propertyToCopy.GetGetMethod()));
			if (propertyToCopy.CanWrite)
				result.SetSetMethod((MethodBuilder)CopyMethod(propertyToCopy.GetSetMethod(true)));

			return result;
		}

		void AnalyzeMethodBody(MethodBase methodToCopy)
		{
			MethodBody methodBody=methodToCopy.GetMethodBody();
			if (methodBody==null)
				return;

			IlReader.IlInstruction[] instructions=new IlReader().ReadMethod(methodBody,methodToCopy);
			foreach (IlReader.IlInstruction instruction in instructions)
			{
				if (instruction.Data is FieldInfo)
					CopyField((FieldInfo)instruction.Data);
				else if (instruction.Data is MethodInfo)
					CopyMethod((MethodInfo)instruction.Data);
				else if (instruction.Data is Type)
					CopyType((Type)instruction.Data);
				else if (instruction.Data is ConstructorInfo)
					CopyConstructor((ConstructorInfo)instruction.Data);
			}
		}

		internal void FinalizeCopies()
		{
			foreach (KeyValuePair<ConstructorInfo,ConstructorInfo> item in _copiedConstructors)
			{
				ConstructorBuilder cb=item.Value as ConstructorBuilder;
				if (cb!=null)
					CopyMethodBody(item.Key,() => cb.GetILGenerator(),(val) => cb.InitLocals=val);
			}

			foreach (KeyValuePair<MethodInfo,MethodInfo> item in _copiedMethods)
			{
				MethodBuilder mb=item.Value as MethodBuilder;
				if (mb!=null)
					CopyMethodBody(item.Key,() => mb.GetILGenerator(),(val) => mb.InitLocals=val);
			}

			foreach (KeyValuePair<Type,TypeBuilder> item in _copiedTypes)
				if (item.Key.IsEnum)
					item.Value.CreateType();
			foreach (KeyValuePair<Type,TypeBuilder> item in _copiedTypes)
				if (!item.Key.IsEnum)
					item.Value.CreateType();
		}

		void CopyMethodBody(MethodBase methodToCopy,Func<ILGenerator> getGenDel,Action<bool> setInitLocalsDel)
		{
			MethodBody methodBodyToCopy=methodToCopy.GetMethodBody();
			if (methodBodyToCopy==null)
				return;

			ILGenerator gen=getGenDel();
			foreach (LocalVariableInfo item in methodBodyToCopy.LocalVariables)
				gen.DeclareLocal(CopyType(item.LocalType),item.IsPinned);
			setInitLocalsDel(methodBodyToCopy.InitLocals);

			WriteMethodInstructions(gen,new IlReader().ReadMethod(methodBodyToCopy,methodToCopy));
		}

		void WriteMethodInstructions(ILGenerator gen,IlReader.IlInstruction[] instructions)
		{
			Dictionary<int,List<Label>> labels=new Dictionary<int,List<Label>>();

			List<Label> labelsOffset;
			foreach (IlReader.IlInstruction instruction in instructions)
			{
				if (labels.TryGetValue(instruction.Address,out labelsOffset))
					foreach (Label item in labelsOffset)
						gen.MarkLabel(item);

				if (instruction.Data==null)
					gen.Emit(instruction.Op);
				else if (instruction.Data is FieldInfo)
				{
					FieldInfo fi=(FieldInfo)instruction.Data;
					FieldBuilder fi2;
					if (_copiedFields.TryGetValue(fi,out fi2))
						fi=fi2;
					gen.Emit(instruction.Op,fi);
				}
				else if (instruction.Data is Int32)
					gen.Emit(instruction.Op,(Int32)instruction.Data);
				else if (instruction.Data is Int64)
					gen.Emit(instruction.Op,(Int64)instruction.Data);
				else if (instruction.Data is MethodInfo)
				{
					MethodInfo mi=(MethodInfo)instruction.Data;
					if (IsDelegateDescendant(mi.DeclaringType))
						mi=CopyType(mi.DeclaringType).GetMethod(mi.Name);
					else
					{
						MethodInfo mi2;
						if ((_copiedMethods.TryGetValue(mi,out mi2)))
							mi=mi2;
					}
					gen.Emit(instruction.Op,mi);
				}
				else if (instruction.Data is double)
					gen.Emit(instruction.Op,(double)instruction.Data);
				else if (instruction.Data is String)
					gen.Emit(instruction.Op,(String)instruction.Data);
				else if (instruction.Data is Type)
				{
					Type ti=(Type)instruction.Data;
					if (IsDelegateDescendant(ti))
						ti=CopyType(ti);
					else
					{
						TypeBuilder ti2;
						if (_copiedTypes.TryGetValue(ti,out ti2))
							ti=ti2;
						Type ti3;
						if (_createdTypes.TryGetValue(ti,out ti3))
							ti=ti3;
					}
					gen.Emit(instruction.Op,ti);
				}
				else if (instruction.Data is short)
					gen.Emit(instruction.Op,(short)instruction.Data);
				else if (instruction.Data is byte)
					gen.Emit(instruction.Op,(byte)instruction.Data);
				else if (instruction.Data is float)
					gen.Emit(instruction.Op,(float)instruction.Data);
				else if (instruction.Data is ConstructorInfo)
				{
					ConstructorInfo ci=(ConstructorInfo)instruction.Data;
					ConstructorInfo ci2;
					if (_copiedConstructors.TryGetValue(ci,out ci2))
						ci=ci2;
					gen.Emit(instruction.Op,ci);
				}
				else if (instruction.Op==OpCodes.Switch)
				{
					int[] labelsOffsets=(int[])instruction.Data;
					int a=0;
					Label[] nowLabels=new Label[labelsOffsets.Length];
					int offset=instructions[instruction.InstructionIndex+1].Address;
					foreach (int item in labelsOffsets)
					{
						if (!labels.TryGetValue(item+offset,out labelsOffset))
						{
							labelsOffset=new List<Label>();
							labels.Add(item+offset,labelsOffset);
						}
						Label l=gen.DefineLabel();
						nowLabels[a++]=l;
						labelsOffset.Add(l);
					}
					gen.Emit(instruction.Op,nowLabels);
				}
				else
					throw new NotImplementedException();
			}
		}

		bool IsDelegateDescendant(Type type)
		{
			return (typeof(Delegate).IsAssignableFrom(type))&&(typeof(Delegate)!=type);
		}

		static BindingFlags _bindingFlags=BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static|BindingFlags.DeclaredOnly;
		Type CopyAllMembers(Type typeToCopy,TypeBuilder typeBldr)
		{
			foreach (ConstructorInfo item in typeToCopy.GetConstructors(_bindingFlags))
			{
				ConstructorBuilder cb=(ConstructorBuilder)CopyConstructor(item);
				AnalyzeMethodBody(item);
				CopyMethodBody(item,() => cb.GetILGenerator(),(val) => cb.InitLocals=val);

				if (_copiedConstructors.ContainsKey(item))
					_copiedConstructors.Remove(item);
			}

			foreach (FieldInfo item in typeToCopy.GetFields(_bindingFlags))
				CopyField(item);

			foreach (EventInfo item in typeToCopy.GetEvents(_bindingFlags))
				CopyEvent(item);

			foreach (PropertyInfo item in typeToCopy.GetProperties(_bindingFlags))
				CopyProperty(item);

			foreach (MethodInfo item in typeToCopy.GetMethods(_bindingFlags))
			{
				MethodBuilder mb=(MethodBuilder)CopyMethod(item);
				AnalyzeMethodBody(item);
				CopyMethodBody(item,() => mb.GetILGenerator(),(val) => mb.InitLocals=val);

				if (_copiedMethods.ContainsKey(item))
					_copiedMethods.Remove(item);
			}

			/ *foreach (Type item in typeToCopy.GetNestedTypes(bindingFlags))
				CopyType(modBldr,item);* /

			if (HaveAttribute(typeToCopy,typeof(CopyWholeClassCreateAttribute)))
			{
				Type result=typeBldr.CreateType();
				_copiedTypes.Remove(typeToCopy);
				_createdTypes.Add(typeToCopy,result);
				return result;
			}

			return typeBldr;
		}

		bool HaveAttribute(Type type,Type attr)
		{
			return type.GetCustomAttributes(attr,true).Length!=0;
		}

		#region IlReader
		internal class IlReader
		{
			private static readonly Dictionary<short,OpCode> _instructionLookup=new Dictionary<short,OpCode>();
			Module _module;
			bool _declaringTypeIsGeneric;
			Type[] _typeGenericArguments;
			bool _methodIsGeneric;
			Type[] _methodGenericArguments;

			static IlReader()
			{
				FillLookupTable();
			}

			internal IlInstruction[] ReadMethod(MethodBody methodBody,MethodBase methodBase)
			{
				_module=methodBase.Module;
				Type declaringType=methodBase.DeclaringType;
				_declaringTypeIsGeneric=declaringType.IsGenericType;
				_typeGenericArguments=_declaringTypeIsGeneric?declaringType.GetGenericArguments():null;
				_methodIsGeneric=methodBase.IsGenericMethod;
				_methodGenericArguments=_methodIsGeneric?methodBase.GetGenericArguments():null;

				List<IlInstruction> result=new List<IlInstruction>();

				byte[] instructionBytes=methodBody.GetILAsByteArray();
				int instructionIndex=0;
				int startAddress;
				for (int position=0;position<instructionBytes.Length;)
				{
					startAddress=position;
					short operationData=instructionBytes[position];
					if (IsInstructionPrefix(operationData))
						operationData=(short)((operationData<<8)|instructionBytes[++position]);

					position++;

					OpCode code;
					if (!_instructionLookup.TryGetValue(operationData,out code))
						throw new InvalidProgramException(string.Format("0x{0:X2} is not a valid op code.",operationData));

					int dataSize=GetSize(code.OperandType);
					byte[] data=new byte[dataSize];
					Buffer.BlockCopy(instructionBytes,position,data,0,dataSize);
					object objData=this.GetData(code,data);
					position+=dataSize;

					if (code.OperandType==OperandType.InlineSwitch)
					{
						dataSize=(int)objData;
						int[] labels=new int[dataSize];
						for (int index=0;index<labels.Length;index++)
						{
							labels[index]=BitConverter.ToInt32(instructionBytes,position);
							position+=4;
						}

						objData=labels;
					}

					result.Add(new IlInstruction(code,data,startAddress,objData,instructionIndex++));
				}

				return result.ToArray();
			}

			bool IsInstructionPrefix(short value)
			{
				return ((value&OpCodes.Prefix1.Value)==OpCodes.Prefix1.Value)||((value&OpCodes.Prefix2.Value)==OpCodes.Prefix2.Value)
					||((value&OpCodes.Prefix3.Value)==OpCodes.Prefix3.Value)||((value&OpCodes.Prefix4.Value)==OpCodes.Prefix4.Value)
					||((value&OpCodes.Prefix5.Value)==OpCodes.Prefix5.Value)||((value&OpCodes.Prefix6.Value)==OpCodes.Prefix6.Value)
					||((value&OpCodes.Prefix7.Value)==OpCodes.Prefix7.Value)||((value&OpCodes.Prefixref.Value)==OpCodes.Prefixref.Value);
			}

			private static int GetSize(OperandType operandType)
			{
				switch (operandType)
				{
					case OperandType.InlineNone:
						return 0;
					case OperandType.ShortInlineBrTarget:
					case OperandType.ShortInlineI:
					case OperandType.ShortInlineVar:
						return 1;
					case OperandType.InlineVar:
						return 2;
					case OperandType.InlineBrTarget:
					case OperandType.InlineField:
					case OperandType.InlineI:
					case OperandType.InlineMethod:
					case OperandType.InlineSig:
					case OperandType.InlineString:
					case OperandType.InlineSwitch:
					case OperandType.InlineTok:
					case OperandType.InlineType:
					case OperandType.ShortInlineR:
						return 4;
					case OperandType.InlineI8:
					case OperandType.InlineR:
						return 8;
					default:
						return 0;
				}
			}

			private object GetData(OpCode code,byte[] rawData)
			{
				object data=null;
				switch (code.OperandType)
				{
					case OperandType.InlineField:
						if ((_declaringTypeIsGeneric)||(_methodIsGeneric))
							data=_module.ResolveField(BitConverter.ToInt32(rawData,0),_typeGenericArguments,_methodGenericArguments);
						else
							data=_module.ResolveField(BitConverter.ToInt32(rawData,0));
						break;
					case OperandType.InlineSwitch:
						data=BitConverter.ToInt32(rawData,0);
						break;
					case OperandType.InlineBrTarget:
					case OperandType.InlineI:
						data=BitConverter.ToInt32(rawData,0);
						break;
					case OperandType.InlineI8:
						data=BitConverter.ToInt64(rawData,0);
						break;
					case OperandType.InlineMethod:
						if ((_declaringTypeIsGeneric)||(_methodIsGeneric))
							data=_module.ResolveMethod(BitConverter.ToInt32(rawData,0),_typeGenericArguments,_methodGenericArguments);
						else
							data=_module.ResolveMethod(BitConverter.ToInt32(rawData,0));
						break;
					case OperandType.InlineR:
						data=BitConverter.ToDouble(rawData,0);
						break;
					case OperandType.InlineSig:
						data=_module.ResolveSignature(BitConverter.ToInt32(rawData,0));
						break;
					case OperandType.InlineString:
						data=_module.ResolveString(BitConverter.ToInt32(rawData,0));
						break;
					case OperandType.InlineTok:
					case OperandType.InlineType:
						if ((_declaringTypeIsGeneric)||(_methodIsGeneric))
							data=_module.ResolveType(BitConverter.ToInt32(rawData,0),_typeGenericArguments,_methodGenericArguments);
						else
							data=_module.ResolveType(BitConverter.ToInt32(rawData,0));
						break;
					case OperandType.InlineVar:
						data=BitConverter.ToInt16(rawData,0);
						break;
					case OperandType.ShortInlineVar:
					case OperandType.ShortInlineI:
					case OperandType.ShortInlineBrTarget:
						data=rawData[0];
						break;
					case OperandType.ShortInlineR:
						data=BitConverter.ToSingle(rawData,0);
						break;
				}
				return data;
			}

			static void FillLookupTable()
			{
				// Might be better to do an array lookup.  Use a seperate arrary for instructions without a prefix and array for each prefix.
				FieldInfo[] fields=typeof(OpCodes).GetFields(BindingFlags.Static|BindingFlags.Public);
				foreach (FieldInfo field in fields)
				{
					OpCode code=(OpCode)field.GetValue(null);
					_instructionLookup.Add(code.Value,code);
				}
			}

			[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
			internal struct IlInstruction
			{
				private readonly OpCode operationCode; // 40.  56-64.  The entire structure is very big.  maybe do array lookup for opcode instead.
				private readonly byte[] instructionRawData;
				private readonly object instructionData;
				private readonly int instructionAddress;
				private readonly int index;

				internal IlInstruction(OpCode code,byte[] instructionRawData,int instructionAddress,object instructionData,int index)
				{
					this.operationCode=code;
					this.instructionRawData=instructionRawData;
					this.instructionAddress=instructionAddress;
					this.instructionData=instructionData;
					this.index=index;
				}

				public OpCode Op { get { return this.operationCode; } }
				public byte[] RawData { get { return this.instructionRawData; } }
				public object Data { get { return this.instructionData; } }
				public int Address { get { return this.instructionAddress; } }
				public int InstructionIndex { get { return this.index; } }

				public int DataValue
				{
					get
					{
						if (this.Data!=null)
						{
							if (this.Data is byte)
								return (byte)this.Data;
							else if (this.Data is short)
								return (short)this.Data;
							else if (this.Data is int)
								return (int)this.Data;
						}
						return 0;
					}
				}

				public int Length { get { return this.Op.Size+(this.RawData==null?0:this.RawData.Length); } }

				public override string ToString()
				{
					StringBuilder builder=new StringBuilder();
					builder.AppendFormat("0x{0:x4} {1,-10}",this.Address,this.Op.Name);

					if (this.Data!=null)
						builder.Append(this.Data.ToString());

					if (this.RawData!=null&&this.RawData.Length>0)
					{
						builder.Append(" [0x");
						for (int i=this.RawData.Length-1;i>=0;i--)
							builder.Append(this.RawData[i].ToString("x2",System.Globalization.CultureInfo.InvariantCulture));
						builder.Append(']');
					}

					return builder.ToString();
				}
			}
		}
		#endregion IlReader
	}
}
*/